﻿using System;
using System.Collections.Generic;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.DB;
using YJKArchUtils.Utils;

namespace YJKArchUtils.Common
{
	public class EdgeLoopOffsetEditor
	{
		public EdgeLoopOffsetEditor(Autodesk.Revit.ApplicationServices.Application app)
		{
			this.m_App = app;
		}

		public List<LoopEdge> OffsetEdgeLoop(List<LoopEdge> loop, double offset)
		{
			List<XYZ> list = new List<XYZ>();
			foreach (LoopEdge loopEdge in loop)
			{
				list.Add(loopEdge.StartPoint);
				if (loopEdge.IsArc)
				{
					XYZ item = Geometry.CalculatMidPoint(loopEdge.StartPoint, loopEdge.EndPoint, loopEdge.Center(), loopEdge.Normal());
					list.Add(item);
				}
			}
			List<LoopEdge> result = new List<LoopEdge>();
			EdgeLoopAnalyser.RightHandwise rightHandwise = EdgeLoopAnalyser.RightHandwise._AntiClockwise;
			if (!EdgeLoopAnalyser.JudgeRightHandwise(list, ref rightHandwise))
			{
				return result;
			}
			if (rightHandwise == EdgeLoopAnalyser.RightHandwise._Clockwise)
			{
				offset = -offset;
			}
			result = this.OffsetEdges(loop, offset);
			this.ResetLoopEdgeVertex(ref result);
			return result;
		}

		private List<LoopEdge> OffsetEdges(List<LoopEdge> loop, double offset)
		{
			List<LoopEdge> list = new List<LoopEdge>();
			for (int i = 0; i < loop.Count; i++)
			{
				LoopEdge loopEdge = loop[i];
				if (loopEdge.TheEdgeType == LoopEdge.EdgeType.ET_Fixed)
				{
					LoopEdge item = new LoopEdge(loopEdge);
					list.Add(item);
				}
				else
				{
					XYZ startPoint = loopEdge.StartPoint;
					XYZ endPoint = loopEdge.EndPoint;
					if (loopEdge.IsArc)
					{
						XYZ xyz = loopEdge.Center();
						double length = (xyz - startPoint).GetLength();
						double num = length + offset;
						if (loopEdge.Normal().IsAlmostEqualTo(XYZ.BasisZ))
						{
							num = length - offset;
						}
						XYZ xyz2 = (startPoint - xyz).Normalize() * num;
						XYZ xyz3 = (endPoint - xyz).Normalize() * num;
						XYZ startPoint2 = xyz + xyz2;
						XYZ endPoint2 = xyz + xyz3;
						LoopEdge item2 = new LoopEdge(startPoint2, endPoint2, loopEdge.Bulge, loopEdge.CurveId, loopEdge.TheEdgeType);
						list.Add(item2);
					}
					else
					{
						XYZ xyz4 = Geometry.RotateTo((endPoint - startPoint).Normalize(), Math.PI*.5, XYZ.BasisZ) * offset;
						XYZ startPoint3 = startPoint + xyz4;
						XYZ endPoint3 = endPoint + xyz4;
						LoopEdge item3 = new LoopEdge(startPoint3, endPoint3, 0.0, loopEdge.CurveId, loopEdge.TheEdgeType);
						list.Add(item3);
					}
				}
			}
			return list;
		}

		private void ResetLoopEdgeVertex(ref List<LoopEdge> loop)
		{
			for (int i = 0; i < loop.Count; i++)
			{
				LoopEdge loopEdge = loop[i];
				int index = i + 1;
				if (i == loop.Count - 1)
				{
					index = 0;
				}
				LoopEdge loopEdge2 = loop[index];
				if (this.ResetOneVertex(ref loopEdge, ref loopEdge2))
				{
					loop[i] = loopEdge;
					loop[index] = loopEdge2;
				}
				else
				{
					LoopEdge item = new LoopEdge(loopEdge.EndPoint, loopEdge2.StartPoint, 0.0, null, LoopEdge.EdgeType.ET_Fixed);
					loop.Insert(index, item);
					i++;
				}
			}
		}

		private bool ResetOneVertex(ref LoopEdge curEdge, ref LoopEdge nextEdge)
		{
			if (curEdge.EndPoint.IsAlmostEqualTo(nextEdge.StartPoint))
			{
				return true;
			}
			Curve curve = curEdge.ConvertToCurve(this.m_App);
			if (null == curve)
			{
				return false;
			}
			Curve curve2 = nextEdge.ConvertToCurve(this.m_App);
			if (null == curve2)
			{
				return false;
			}
			XYZ curNode = Geometry.CalculatMidPoint(curEdge.EndPoint, nextEdge.StartPoint);
			XYZ xyz;
			if (curEdge.IsArc && nextEdge.IsArc)
			{
				xyz = Geometry.IntersectWithTwoCurves(curve, curve2, curNode, false, false, this.m_App);
			}
			else
			{
				xyz = Geometry.IntersectWithTwoCurves(curve, curve2, curNode, true, true, this.m_App);
			}
			if (xyz == null)
			{
				return false;
			}
			curEdge.EndPoint = xyz;
			nextEdge.StartPoint = xyz;
			return true;
		}

		private Application m_App;
	}
}
